package cn.com.bluemoon.daps.model.controller;


import cn.com.bluemoon.daps.api.sys.RemoteSysConfigService;
import cn.com.bluemoon.daps.common.datascope.BmPermission;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.enums.DatabaseType;
import cn.com.bluemoon.daps.model.dto.ContrastTableInfo;
import cn.com.bluemoon.daps.model.dto.ModelTableInfoDto;
import cn.com.bluemoon.daps.model.dto.SubordinateKeyDto;
import cn.com.bluemoon.daps.model.entity.*;
import cn.com.bluemoon.daps.model.service.*;
import cn.com.bluemoon.daps.model.utils.SqlUtils;
import cn.com.bluemoon.daps.model.utils.factory.impl.table.AbsTableScript;
import cn.com.bluemoon.daps.model.utils.factory.impl.table.HiveTableScript;
import cn.com.bluemoon.daps.model.utils.factory.impl.table.MysqlTableScript;
import cn.com.bluemoon.daps.model.utils.factory.impl.table.PostgreTableScript;
import cn.com.bluemoon.daps.model.vo.SearchModelApplicationVo;
import cn.com.bluemoon.daps.model.vo.SearchModelVersionVo;
import cn.com.bluemoon.daps.standard.dto.ApplicationModelDto;
import cn.com.bluemoon.daps.sync.vo.dev2model.MetaTableOut;
import cn.com.bluemoon.daps.system.entity.DapSystemConfigSandbox;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.parser.ParserException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestController
@Slf4j
@RequestMapping("/dapModel")
@Api(tags = {"模型版本对比"})
public class DapDataModelContrastController {

    @Resource
    DapDataModelVersionService dapDataModelVersionService;

    @Resource
    DapDataModelRecordService dapDataModelRecordService;

    @Resource
    DapDataModelTableFieldService dapDataModelTableFieldService;

    @Resource
    DapDataModelSubordinateKeyService dapDataModelSubordinateKeyService;

    @Resource
    DapDataModelTablePartitionService dapDataModelTablePartitionService;

    @Resource
    DapDataModelTableService dapDataModelTableService;

    @Resource
    RemoteSysConfigService remoteSysConfigService;

    @PostMapping("version/list")
    @ApiOperation("版本发布记录列表")
    @ApiResponses(value = {@ApiResponse(code = 500, message = "错误原因信息", response = String.class),
            @ApiResponse(code = 200, message = "ok", responseContainer = "List", response = DapDataModelRecord.class)})
    @BmPermission(value = "model:publish:list", name = "模型发布记录")
    public ResultBean<IPage<DapDataModelRecord>> applicationList(@RequestBody @Valid SearchModelVersionVo vo){

        // 查询列表信息
        IPage<DapDataModelRecord> list = dapDataModelRecordService.getVersionRecord(vo);
        return ResultBean.ok(list);
    }

    @GetMapping("version/contrast")
    @ApiOperation("版本对比接口")
    @ApiResponses(value = {@ApiResponse(code = 500, message = "错误原因信息", response = String.class),
            @ApiResponse(code = 200, message = "ok", responseContainer = "List", response = ContrastTableInfo.class)})
    @BmPermission(value = "model:publish:list", name = "表版本对比")
    public ResultBean<List<ContrastTableInfo>> versionContrast(@RequestParam("tableId") @ApiParam("表id") @NotNull(message = "表id不允许为空") String tableId,
                                                                     @RequestParam("recordIdNew") @ApiParam("新发布记录id") @NotNull(message = "新发布记录id不允许为空") String recordIdNew,
                                                                     @RequestParam("recordIdOld") @ApiParam("旧发布记录id") @NotNull(message = "旧发布记录id不允许为空") String recordIdOld){
        // 表对比
        List<ContrastTableInfo> list = dapDataModelVersionService.versionContrast(tableId, recordIdNew, recordIdOld);
        if(list.isEmpty()){
            return ResultBean.error("当前两个版本表结构不存在差异");
        }
        return ResultBean.ok(list);
    }

    @BmPermission(value = "model:table:export", name = "检查sql语法")
    @GetMapping("modelTable/sql/check")
    @ApiOperation(value = "检查sql语法")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = String.class)})
    public ResultBean<String> checkSql(@RequestParam("tableId") @ApiParam("表id") @NotNull(message = "表id不为空") String tableId,
                                        @RequestParam("modelId") @ApiParam("模型id") @NotNull(message = "模型id不为空") String modelId,
                                        @RequestParam("databaseType") @ApiParam("数据库类型") DatabaseType databaseType){

        String sql = null;
        DbType dbType = databaseType.equals(DatabaseType.MYSQL) ? DbType.mysql :
                databaseType.equals(DatabaseType.PGSQL) ? DbType.postgresql : DbType.hive;
        // 根据模型表id查询数据库中的表和字段信息
        ModelTableInfoDto tableInfo = dapDataModelTableFieldService.getTableInfo(tableId);
        if(databaseType.equals(DatabaseType.HIVE)){
            // 根据模型表id获取分区信息
            List<DapDataModelTablePartition> partitionList = dapDataModelTablePartitionService.getPartitionList(tableId);
            HiveTableScript hiveTableScript = new HiveTableScript();
            sql = hiveTableScript.createTableScript(tableInfo, null, partitionList);
        }else{
            // 根据模型表id获取索引信息
            List<SubordinateKeyDto> keyList = dapDataModelSubordinateKeyService.getKeyList(tableId);
            AbsTableScript script = databaseType.equals(DatabaseType.MYSQL) ? new MysqlTableScript() : new PostgreTableScript();
            // 生成sql语句
            sql = script.createTableScript(tableInfo, keyList, null);
        }
        // 检查语法
        try {
            if(StringUtils.isNotBlank(sql)){
                SQLUtils.parseStatements(sql,dbType);
            }
        }catch (ParserException e){
            return ResultBean.error(e.getMessage());
        }
        // 获得沙箱环境进行执行
        if(databaseType.equals(DatabaseType.MYSQL)){
            ResultBean<DapSystemConfigSandbox> resultBean = remoteSysConfigService.sandboxConfig();
            if (null != resultBean.getContent()){
                DapSystemConfigSandbox content = resultBean.getContent();
                String url = content.getUrl(DatabaseType.MYSQL,"sql_execute");
                // 创建沙箱环境数据库
                boolean flag = SqlUtils.createDatabase(content.getUrl(DatabaseType.MYSQL,""), content.decryptPassword(), content.getUsername());
                if(flag){
                    return SqlUtils.createTable(url,content.decryptPassword(), content.getUsername(), sql, tableInfo.getEngName());
                }else {
                    return ResultBean.error("数据库创建失败");
                }
            }
        }
        return ResultBean.ok();
    }

    @GetMapping("/table/version/list")
    @ApiOperation("表历史版本记录")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapDataModelRecord.class)})
    @BmPermission(value = "model:publish:list", name = "")
    public ResultBean<List<DapDataModelRecord>> tableVersionList(@RequestParam("tableId") @NotNull(message = "表id不能为空") String tableId){

        // 查询模型id
        DapDataModelTable table = dapDataModelTableService.getBaseMapper().selectById(tableId);
        // 查询版本记录
        List<DapDataModelRecord> dapDataModelRecords = dapDataModelRecordService.getBaseMapper().selectList(new LambdaQueryWrapper<DapDataModelRecord>()
                .eq(DapDataModelRecord::getModelId, table.getDataModelId()).eq(DapDataModelRecord::getPublicStatus, 1));
        return ResultBean.ok(dapDataModelRecords);
    }
}
